/**
 * Copyright © 2014 Creativor Studio.
 * About license information, please see LICENSE.txt.
 */
package org.rayson.share.rpc;

import java.util.Map;

import org.rayson.api.Invocation;
import org.rayson.api.KeyValues;
import org.rayson.api.annotation.NotNull;
import org.rayson.api.exception.ProtocolException;
import org.rayson.server.common.parser.ParameterParser;
import org.rayson.server.common.parser.ParameterParserFactory;
import org.rayson.share.RaysonConstants;
import org.rayson.share.http.HttpConstants;
import org.rayson.share.http.HttpHeader;
import org.rayson.share.http.HttpRequest;

/**
 * TODO Add type description here.
 *
 * @author creativor
 */
public class InvocationImpl implements Invocation {

	private static void addHeaders(final InvocationImpl invocation,
			final Map<String, HttpHeader> headers) {
		for (final HttpHeader header : headers.values()) {
			invocation.headers.put(header.getName(), header.getValue());
		}
	}

	private static void addParameters(final InvocationImpl invocation,
			final byte[] paramsData) throws ProtocolException {
		final ParameterParser parser = ParameterParserFactory.getParser();
		parser.parse(paramsData, invocation.parameters);
	}

	public static Invocation parse(@NotNull final HttpRequest msg)
			throws ProtocolException {
		final InvocationImpl invocation = new InvocationImpl();
		final HttpHeader versionHeader = msg
				.getHeader(RaysonConstants.PROTOCOL_VERSION_HEADER_NAME);
		invocation.version = versionHeader == null ? RaysonConstants.DEFAULT_PROTOCOL_VERSION
				: Short.valueOf(versionHeader.getValue());
		final String uri = msg.getStartLine().getUri();
		// Parse the uri.
		final int lastSlash = uri.indexOf(HttpConstants.SLASH_TOKEN, 1);
		final int lastQuery = uri.indexOf(HttpConstants.QUERY_TOKEN);
		invocation.service = uri.substring(0, lastSlash);
		invocation.method = (lastQuery == -1) ? uri.substring(lastSlash + 1)
				: uri.substring(lastSlash + 1, lastQuery);
		addHeaders(invocation, msg.getHeaders());
		// Parse parameters.
		final byte[] uriParams = (lastQuery == -1) ? new byte[0] : uri
				.substring(lastQuery + 1).getBytes();
		final byte[] bodyParams = msg.getBody();
		addParameters(invocation, uriParams);
		addParameters(invocation, bodyParams);
		return invocation;
	}

	private short version = 0;

	private final KeyValues headers;
	private String method;
	private final KeyValues parameters;
	private String service;

	private InvocationImpl() {
		headers = new KeyValues();
		parameters = new KeyValues();
	}

	@Override
	public KeyValues getHeaders() {
		return headers;
	}

	@Override
	public String getMethod() {
		return method;
	}

	@Override
	public KeyValues getParameters() {
		return parameters;
	}

	@Override
	public String getService() {
		return service;
	}

	@Override
	public short getVersion() {
		return version;
	}

	@Override
	public String toString() {
		final StringBuffer sb = new StringBuffer();
		final Object[] values = { service, method, version, headers };
		final String[] keys = { "service", "method", "version", "headers" };
		final int keyLen = keys.length;
		sb.append("{");
		for (int i = 0; i < keyLen; i++) {
			sb.append(keys[i]);
			sb.append(":");
			sb.append(values[i]);
			if (i != keyLen - 1)
				sb.append(", ");
		}
		sb.append("}");
		return sb.toString();
	}
}